﻿using System;
using System.Text;
using System.Diagnostics;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;

namespace DbToPbiSvc.Logging
{
    /// <summary>
    /// Log file helper 
    /// </summary>
    /// <example>
    /// Simple implementation for debug log info and error log info
    /// <code>
    /// using DbToPbiSvc.Logging;
    /// 
    /// public void myMethod()
    /// {
    /// 
    ///     try
    ///     {
    ///         LogHelper.TraceDebugInfo("IN");
    ///             
    ///         ...
    /// 
    ///     }
    ///     catch (Exception exc)
    ///     {
    ///         LogHelper.TraceError(exc);
    ///     }
    ///     finally
    ///     {
    ///         LogHelper.TraceDebugInfo("OUT");
    ///     }
    /// 
    /// }
    /// 
    /// </code>
    /// </example>
    public static class LogHelper
    {

        /// <summary>Enable detailed trace (Debug Category)</summary>
        private static bool TraceEnabled;

        /// <summary>Application config configuration name: DebugTraceEnabled</summary>
        private const string DebugTraceEnabledPropname = "DebugTraceEnabled";

        /// <summary>Application config trace category: Error Category</summary>
        private const string ErrorCategory = "Error Category";
        /// <summary>Application config trace category: Debug Category</summary>
        private const string DebugCategory = "Debug Category";
        /// <summary>Application config trace category: Functional Category</summary>
        private const string FunctionalCategory = "Functional Category";

        /// <summary>
        /// Enable/Disable debug trace with current application settings.
        /// </summary>
        static LogHelper()
        {
            try
            {
                TraceEnabled = (ConfigurationManager.AppSettings[DebugTraceEnabledPropname].ToUpper() == "TRUE");
            }
            catch (Exception)
            {
                // ignored
            }
        }

        /// <summary>
        /// Trace errors into the "DebugTrace.log" file and Windows application event log.
        /// </summary>
        /// <param name="exc">Exception fired</param>
        public static void TraceError(Exception exc)
        {

            LogEntry errorLog = new LogEntry();
            StringBuilder messageLog = new StringBuilder();

            try
            {

                // Starting main exception
                int i = 1;
                Exception currentExc = exc;

                while (currentExc != null)
                {
                    // Preparing spaces for indentation
                    string space = "\t";
                    int numberOfSpaces = i * 2;
                    for (int counter = 0; counter < numberOfSpaces; counter++) { space += space; }

                    // Composing message
                    messageLog.AppendLine();
                    messageLog.AppendLine(string.Concat(space, "-----------------------------------"));
                    messageLog.AppendLine(string.Concat(space, "Namespace    : ", currentExc.TargetSite.ReflectedType?.FullName));
                    messageLog.AppendLine(string.Concat(space, "Method       : ", currentExc.TargetSite.Name));
                    messageLog.AppendLine(string.Concat(space, "Message      : ", currentExc.Message));
                    messageLog.AppendLine(string.Concat(space, "Stack Trace  : ", currentExc.StackTrace));
                    messageLog.AppendLine(string.Concat(space, "-----------------------------------"));

                    // Get inner exception
                    currentExc = currentExc.InnerException;
                    i++;
                }

                // Retrieving the caller informations
                var callerStackFrame = new StackFrame(1, true);
                var errorMethod = callerStackFrame.GetMethod();

                // Using the appropriate categories
                errorLog.Categories.Add(ErrorCategory);
                errorLog.Categories.Add(DebugCategory);

                errorLog.Message = messageLog.ToString();
                errorLog.Severity = TraceEventType.Error;
                errorLog.Title = string.Concat(errorMethod.ReflectedType?.FullName, ".", errorMethod.Name);

                Logger.Write(errorLog);
            }
            catch (Exception)
            {
                // ignored
            }
        }

        /// <summary>
        /// Trace the functional info into the designed log's file.
        /// </summary>
        /// <param name="messageLog">Functional info</param>
        /// <example>
        /// This code show how to write a functional info. The functional
        /// info are always written in a separated log file.
        /// <code>
        /// using DbToPbiSvc.Logging;
        /// 
        /// private void myMethod()
        /// {
        /// 
        ///   try
        ///   {
        ///     LogHelper.TraceDebugInfo("IN");
        ///   
        ///     ...
        ///     
        ///     LogHelper.TraceFunctionalInfo("This method log functional info");
        ///
        ///     ...
        ///     
        ///    }
        ///    catch (Exception exc)
        ///    {
        ///      LogHelper.TraceError(exc);
        ///    }
        ///    finally
        ///    {
        ///      LogHelper.TraceDebugInfo("OUT");
        ///    }
        /// 
        /// }
        /// 
        /// </code>
        /// </example>
        public static void TraceFunctionalInfo(string messageLog)
        {

            LogEntry functionalLog = new LogEntry();

            try
            {

                // Retrieving the caller informations
                var callerStackFrame = new StackFrame(1, true);
                var functionalMethod = callerStackFrame.GetMethod();

                // Using the appropriate categories
                functionalLog.Categories.Add(FunctionalCategory);

                functionalLog.Message = messageLog;
                functionalLog.Severity = TraceEventType.Information;
                functionalLog.Title = string.Concat(functionalMethod.ReflectedType?.FullName, ".", functionalMethod.Name);

                Logger.Write(functionalLog);

            }
            catch (Exception)
            {
                // ignored
            }
        }

        /// <summary>
        /// Trace into the debug file the usefull informations for the application's debug.
        /// The message will be written only if "DebugTraceEnabled" web.config application setting
        /// key is equal to "True".
        /// </summary>
        /// <param name="messageLog">Debug message</param>        
        public static void TraceDebugInfo(string messageLog)
        {

            if (!TraceEnabled)
            {
                return;
            }

            LogEntry debugLog = new LogEntry();

            try
            {

                // Retrieving the caller informations
                var callerStackFrame = new StackFrame(1, true);
                var debugMethod = callerStackFrame.GetMethod();

                // Using the appropriate categories
                debugLog.Categories.Add(DebugCategory);

                debugLog.Message = messageLog;
                debugLog.Severity = TraceEventType.Information;
                debugLog.Title = string.Concat(debugMethod.ReflectedType?.FullName, ".", debugMethod.Name);

                Logger.Write(debugLog);

            }
            catch (Exception)
            {
                // ignored
            }
        }

        /// <summary>
        /// Trace a generic message into the debug file and, optionally, into event application log
        /// </summary>
        /// <param name="messageLog">Message to trace</param>
        /// <param name="messageSeverity">Specify message severity (refer to System.Diagnostics.TraceEventType enumeration to possible values)</param>
        /// <param name="writeMessageOnEventLog">If true an event application log entry will be generated</param>        
        public static void TraceGenericMessage(string messageLog, TraceEventType messageSeverity, bool writeMessageOnEventLog)
        {

            LogEntry debugLog = new LogEntry();

            try
            {

                // Retrieving the caller informations
                var callerStackFrame = new StackFrame(1, true);
                var debugMethod = callerStackFrame.GetMethod();

                // Using the appropriate categories
                debugLog.Categories.Add(DebugCategory);

                if (writeMessageOnEventLog)
                {
                    debugLog.Categories.Add(ErrorCategory);
                }

                debugLog.Message = messageLog;
                debugLog.Severity = messageSeverity;
                debugLog.Title = string.Concat(debugMethod.ReflectedType?.FullName, ".", debugMethod.Name);

                Logger.Write(debugLog);

            }
            catch (Exception)
            {
                // ignored
            }
        }
    }
}
